using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using System.Collections.Generic;
using Ltf.Remoting.Commands;
using System.Diagnostics;
using System.Threading;
using System.Reflection;
using Ltf.Remoting.RemoteEvents;
using Ltf.Remoting.Settings;
using System.Text;
using Ltf.Remoting.TeamFoundation;
using Ltf.Remoting.Operations;
using Microsoft.TeamFoundation.VersionControl.Client;
using System.IO;
using Lizard.Remoting.Operations;
using Ltf.Remoting.TFAccess;
using System.Xml.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace Ltf.Remoting.Server
{
	public class ServerFunctions : MarshalByRefObject
	{

		public static RemoteEvents.RemoteEventRaiser RemoteEventRaiser = new Ltf.Remoting.RemoteEvents.RemoteEventRaiser();
		///constructor
		public ServerFunctions()
		{
			;
		}
		///return message reply
		public void ParseFolder(String folderName)
		{
			GenerateOverlayInfo g = new GenerateOverlayInfo(ServerConnections.GetConnectionForPath(folderName), folderName, false);
			g.TestFolder();
			//ThreadStart ts = new ThreadStart(g.TestFolder);
			//Thread t = new Thread(ts);

			//t.Start();
		}

		public string GetLtfMetaFolderName()
		{
			TFSettings settings = (TFSettings)Settings.SettingsFactory.LoadSettings("Server", typeof(TFSettings));
			return settings.LtfMetaFolderName;
		}

		public TFSettings GetSettings()
		{
			return (TFSettings)Settings.SettingsFactory.LoadSettings("Server", typeof(TFSettings));
		}

		public List<LizardChangeset> GetHistory(String fileName)
		{
			TFHistory history;
			if (!fileName.StartsWith("$"))
			{
				ParseSingleFile(fileName);
				history = new TFHistory(fileName);
			}
			else
			{
				TFServerConnection connection = ServerConnections.GetConnectionForPath(fileName);
				Workspace workspace = connection.GetWorkspace(fileName);
				history = new TFHistory(connection, fileName, workspace);
			}
			history.GetHistory();
			List<LizardChangeset> changesList = new List<LizardChangeset>();
			foreach (LizardChangeset lcs in history.Changesets)
				changesList.Add(lcs);
			return changesList;
		}

		[ContextMenu("createworkspace", "Create New Workspace", FileType.NotInWorkspace, FileType.SingleFolder)]
		[ContextMenuUsage(ContextMenuUsage.ExplorerOnly)]
		public void CreateWorkspace(string pathlist)
		{
			RemoteEventRaiser.RaiseOpenMonitorForm
				(this, new RemoteEvents.LizardEventArgs(GetPaths(pathlist), FormTypes.CreateNewWorkSpace));
		}
		[ContextMenu("review", "Lizard Review", FileType.Versioned, FileType.AllFolders)]
		[ContextMenuUsage(ContextMenuUsage.ExplorerOnly)]
		public void LizardReview(string pathlist)
		{
			RemoteEventRaiser.RaiseOpenMonitorForm
				(this, new RemoteEvents.LizardReviewEventArgs(GetPaths(pathlist), ReviewPrimaryFunction.GetLatest, true, true, true, true, false, false, false));
		}


		[ContextMenu("getlatest", "Get Latest (recursive)", FileType.Versioned)]
		[ContextMenuUsage(ContextMenuUsage.ExplorerAndReview)]
		public void GetLatestVersion(string pathlist)
		{
			RemoteEventRaiser.RaiseOpenMonitorForm
				(this, new RemoteEvents.LizardReviewEventArgs(GetPaths(pathlist), ReviewPrimaryFunction.GetLatest, true, true, false, false, false, false, false));
		}

		[ContextMenu("getspecific", "Get Specific Version", FileType.Versioned)]
		[ContextMenuUsage(ContextMenuUsage.ExplorerOnly)]
		public void GetSpecificVersion(string pathlist)
		{
			RemoteEventRaiser.RaiseOpenMonitorForm
				(this, new RemoteEvents.LizardReviewEventArgs(GetPaths(pathlist), ReviewPrimaryFunction.GetSpecific, true, true, false, false, false, true, false));
		}

		[ContextMenu("seperator2", "----------")]
		[ContextMenuUsage(ContextMenuUsage.ExplorerOnly)]
		public void seperator2(string pathlist)
		{
		}

		[ContextMenu("history", "History", FileType.Versioned, FileType.SingleItem)]
		[ContextMenuUsage(ContextMenuUsage.ExplorerAndReview)]
		public void ShowHistory(string pathlist)
		{
			RemoteEventRaiser.RaiseOpenMonitorForm
				(this, new RemoteEvents.LizardEventArgs(GetPaths(pathlist), FormTypes.History));
		}

		[ContextMenu("labels", "Labels", FileType.Versioned, FileType.SingleItem)]
		[ContextMenuUsage(ContextMenuUsage.ExplorerAndReview)]
		public void Lables(string pathlist)
		{
			RemoteEventRaiser.RaiseOpenMonitorForm
				(this, new RemoteEvents.LizardEventArgs(GetPaths(pathlist), FormTypes.Labels));
		}


		[ContextMenu("diff2", "Show Differences", FileType.Unversioned | FileType.NotInWorkspace, FileType.TwoFiles)]
		[ContextMenuUsage(ContextMenuUsage.ExplorerOnly)]
		public void Diff2(string pathlist)
		{
			string[] paths = GetPaths(pathlist);
			string path1 = paths[0];
			string path2 = paths[1];
			FormTypes formType = FormTypes.TwoWayDiff;
			if (Path.GetExtension(path1) == ".dll" | Path.GetExtension(path1) == ".exe")
				formType = FormTypes.ExcutableDiff;
			RemoteEventRaiser.RaiseOpenMonitorForm
				(this, new RemoteEvents.LizardEventArgs(new string[] { path2, path1 }, formType));
		}



		[ContextMenu("diff", "Show Differences", FileType.Versioned, FileType.SingleFile | FileType.TwoFiles)]
		[ContextMenuUsage(ContextMenuUsage.ExplorerOnly)]
		public void Diff(string pathlist)
		{
			string[] paths = GetPaths(pathlist);
			string path1 = paths[0];
			string path2 = null;
			if (paths.Length > 1)
				path2 = paths[1];
			//ShellOperators so = new ShellOperators();
			//so.Diff(path1, path2);

			if (path2 == null)
			{
				Workspace ws = ServerConnections.GetConnectionForPath(path1).GetWorkspace(path1);
				ExtendedItem[] extItems = ws.GetExtendedItems(new ItemSpec[] { new ItemSpec(path1, RecursionType.None) }, DeletedState.Any, ItemType.Any)[0];
				if (extItems.Length > 0)
				{
					ExtendedItem extItem = extItems[0];
					path2 = LizardFileAccess.SetPathVersion(extItem.SourceServerItem, extItem.VersionLocal);
				}

			}
			FormTypes formType = FormTypes.TwoWayDiff;
			if (Path.GetExtension(path1) == ".dll" | Path.GetExtension(path1) == ".exe")
				formType = FormTypes.ExcutableDiff;
			RemoteEventRaiser.RaiseOpenMonitorForm
				(this, new RemoteEvents.LizardEventArgs(new string[] { path2, path1 }, formType));
		}

		[ContextMenu("resolveconflict", "Resolve Conflict", FileType.Conflict, FileType.SingleFile)]
		[ContextMenuUsage(ContextMenuUsage.ExplorerAndReview)]
		public void ResolveConflict(string pathlist)
		{
			string[] paths = GetPaths(pathlist);
			string path1 = paths[0];


			RemoteEventRaiser.RaiseOpenMonitorForm
				(this, new RemoteEvents.LizardEventArgs(new string[] { path1 }, FormTypes.ConflictResolver));
		}


		[ContextMenu("blame", "LizardBlame", FileType.Versioned, FileType.SingleFile)]
		[ContextMenuUsage(ContextMenuUsage.ExplorerAndReview)]
		public void Blame(string pathlist)
		{
			string[] paths = GetPaths(pathlist);
			string path1 = paths[0];

			RemoteEventRaiser.RaiseOpenMonitorForm
				(this, new RemoteEvents.LizardEventArgs(new string[] { path1 }, FormTypes.TwoWayDiff));
		}

		[ContextMenu("seperator3", "----------")]
		[ContextMenuUsage(ContextMenuUsage.ExplorerOnly)]
		public void seperator3(string pathlist)
		{
		}

		[ContextMenu("checkin", "Check In", FileType.Versioned | FileType.Added, FileType.Added | FileType.CheckedOut | FileType.SingleFolder)]
		[ContextMenuUsage(ContextMenuUsage.ExplorerAndReview)]
		public void UndoPending(string pathlist)
		{
			RemoteEventRaiser.RaiseOpenMonitorForm
				(this, new RemoteEvents.LizardReviewEventArgs(GetPaths(pathlist), ReviewPrimaryFunction.CheckIn, true, false, true, true, true, false, false));
		}


		[ContextMenu("checkout", "Check-out", FileType.Versioned, FileType.CheckedIn | FileType.SingleFolder)]
		[ContextMenuUsage(ContextMenuUsage.ExplorerAndReview)]
		public void CheckOut(string pathlist)
		{
			string[] paths = GetPaths(pathlist);
			if (paths.Length > 0)
			{
				TFServerConnection connection = ServerConnections.GetConnectionForPath(paths[0]);
				WorkspaceOperators wso = new WorkspaceOperators(connection, connection.GetWorkspace(paths[0]));
				wso.PendEdit(paths);
			}
		}

		[ContextMenu("checkoutlock", "Check-out/Lock...", FileType.Versioned, FileType.AllFiles | FileType.SingleFolder)]
		[ContextMenuUsage(ContextMenuUsage.ExplorerAndReview)]
		public void CheckOutLock(string pathlist)
		{
			RemoteEventRaiser.RaiseOpenMonitorForm
				(this, new RemoteEvents.LizardEventArgs(GetPaths(pathlist), FormTypes.CheckOutLock));
		}


		[ContextMenu("conflicts", "Review Conflicts", FileType.Versioned, FileType.Added | FileType.CheckedOut | FileType.SingleFolder)]
		[ContextMenuUsage(ContextMenuUsage.ExplorerOnly)]
		public void ReviewConflicts(string pathlist)
		{
			RemoteEventRaiser.RaiseOpenMonitorForm
				(this, new RemoteEvents.LizardReviewEventArgs(GetPaths(pathlist), ReviewPrimaryFunction.ViewConflicts, true, true, true, false, false, false, false));
		}

		[ContextMenu("undopending", "Undo Pending", FileType.Versioned | FileType.Added, FileType.Added | FileType.CheckedOut | FileType.SingleFolder)]
		[ContextMenuUsage(ContextMenuUsage.ExplorerAndReview)]
		public void CheckIn(string pathlist)
		{
			RemoteEventRaiser.RaiseOpenMonitorForm
				(this, new RemoteEvents.LizardReviewEventArgs(GetPaths(pathlist), ReviewPrimaryFunction.Undo, false, false, true, true, false, false, false));
		}

		[ContextMenu("shelve", "Shelve Changes", FileType.Versioned | FileType.Added, FileType.Added | FileType.CheckedOut | FileType.SingleFolder)]
		[ContextMenuUsage(ContextMenuUsage.ExplorerAndReview)]
		public void Shelve(string pathlist)
		{
			RemoteEventRaiser.RaiseOpenMonitorForm
				(this, new RemoteEvents.LizardReviewEventArgs(GetPaths(pathlist), ReviewPrimaryFunction.Shelve, true, false, true, true, true, false, true));
		}


		[ContextMenu("seperator4", "----------")]
		[ContextMenuUsage(ContextMenuUsage.ExplorerOnly)]
		public void seperator4(string pathlist)
		{
		}


		[ContextMenu("add", "Add", FileType.Unversioned, FileType.InWorkspace)]
		[ContextMenuUsage(ContextMenuUsage.ExplorerOnly)]
		public void Add(string pathlist)
		{
			string[] paths = GetPaths(pathlist);
			if (paths.Length > 0)
			{
				TFServerConnection connection = ServerConnections.GetConnectionForPath(paths[0]);
				WorkspaceOperators wso = new WorkspaceOperators(connection, connection.GetWorkspace(paths[0]));
				wso.PendAdd(paths);
				foreach (string path in paths)
				{
					if (Directory.Exists(path))
						ParseFolder(path);
					else if (File.Exists(path))
						ParseSingleFile(path);
				}
			}
		}

		[ContextMenu("delete", "Delete", FileType.Versioned)]
		[ContextMenuUsage(ContextMenuUsage.ExplorerOnly)]
		public void Delete(string pathlist)
		{
			string[] paths = GetPaths(pathlist);
			if (paths.Length > 0)
			{
				TFServerConnection connection = ServerConnections.GetConnectionForPath(paths[0]);
				WorkspaceOperators wso = new WorkspaceOperators(connection, connection.GetWorkspace(paths[0]));
				wso.PendDelete(paths);
			}
		}

		[ContextMenu("rename", "Rename", FileType.Versioned, FileType.SingleItem)]
		[ContextMenuUsage(ContextMenuUsage.ExplorerOnly)]
		public void Rename(string pathlist)
		{
			RemoteEventRaiser.RaiseOpenMonitorForm
				(this, new RemoteEvents.LizardEventArgs(GetPaths(pathlist), FormTypes.RenameTarget));
		}

		[ContextMenu("move", "Move", FileType.Versioned, FileType.SingleItem)]
		[ContextMenuUsage(ContextMenuUsage.ExplorerOnly)]
		public void Move(string pathlist)
		{
			RemoteEventRaiser.RaiseOpenMonitorForm
				(this, new RemoteEvents.LizardEventArgs(GetPaths(pathlist), FormTypes.MoveTarget));
		}


		[ContextMenu("unshelve", "Unshelve Changes", FileType.Versioned)]
		[ContextMenuUsage(ContextMenuUsage.ExplorerAndReview)]
		public void Unshelve(string pathlist)
		{
			RemoteEventRaiser.RaiseOpenMonitorForm
				(this, new RemoteEvents.LizardEventArgs(GetPaths(pathlist), FormTypes.Unshelve));
		}


		[ContextMenu("branch", "Branch", FileType.Versioned, FileType.SingleItem)]
		[ContextMenuUsage(ContextMenuUsage.ExplorerOnly)]
		public void Branch(string pathlist)
		{
			RemoteEventRaiser.RaiseOpenMonitorForm
				(this, new RemoteEvents.LizardEventArgs(GetPaths(pathlist), FormTypes.BranchTarget));
		}


		[ContextMenu("seperator1", "----------")]
		[ContextMenuUsage(ContextMenuUsage.ExplorerOnly)]
		public void seperator1(string pathlist)
		{
		}


		[ContextMenu("comparefolder", "Compare Folder")]
		[ContextMenuUsage(ContextMenuUsage.ExplorerOnly)]
		public void CompareFolder(string pathlist)
		{
			RemoteEventRaiser.RaiseOpenMonitorForm
				(this, new RemoteEvents.LizardEventArgs(GetPaths(pathlist), FormTypes.FolderDiff));
		}

		[ContextMenu("workItems", "Work Items", FileType.InWorkspace)]
		[ContextMenuUsage(ContextMenuUsage.ExplorerOnly)]
		public void WorkItems(string pathlist)
		{
			RemoteEventRaiser.RaiseOpenMonitorForm
				(this, new RemoteEvents.LizardEventArgs(GetPaths(pathlist), FormTypes.WorkItemQueries));
		}

		[ContextMenu("repobrowser", "Browse Repository", FileType.InWorkspace)]
		[ContextMenuUsage(ContextMenuUsage.ExplorerOnly)]
		public void RepoBrowser(string pathlist)
		{
			RemoteEventRaiser.RaiseOpenMonitorForm
				(this, new RemoteEvents.LizardEventArgs(GetPaths(pathlist), FormTypes.RepoBrowser));
		}

		[ContextMenu("statusscan", "Status Scan (Refresh)", FileType.InWorkspace)]
		[ContextMenuUsage(ContextMenuUsage.ExplorerOnly)]
		public void StatusScan(string pathlist)
		{
			StatusScanEx(GetPaths(pathlist), false);
		}

		[ContextMenu("statusscanfull", "Status Scan (Full)", FileType.InWorkspace)]
		[ContextMenuUsage(ContextMenuUsage.ExplorerOnly)]
		public void StatusScanFull(string pathlist)
		{
			StatusScanEx(GetPaths(pathlist), true);
		}


		public void StatusScanEx(string[] paths, bool isForced)
		{
			GenerateOverlayInfo goi = new GenerateOverlayInfo(ServerConnections.GetConnectionForPath(paths[0]));

			List<ItemSpec> itemSpecs = new List<ItemSpec>();
			foreach (string path in paths)
				itemSpecs.Add(new ItemSpec(path, RecursionType.Full));
			Workspace ws = ServerConnections.GetConnectionForPath(paths[0]).GetWorkspace(paths[0]);
			ExtendedItem[][] extItems = ws.GetExtendedItems(itemSpecs.ToArray(), DeletedState.Any, ItemType.Any);
			int count = 0;
			foreach (ExtendedItem[] extItemArray in extItems)
				count += extItemArray.Length;
			ProgressEventArgs args = new ProgressEventArgs("Folder scan", "Scanning TF workspace items", count, 1, true);
			RemoteEventRaiser.RaiseOpenMonitorForm(this, args);
			goi.FileStatusScan += args.IncrementHandler;
			goi.GenerateFileStatuses(extItems, isForced);
		}

		[ContextMenu("properties", "Properties",  FileType.SingleItem)]
		[ContextMenuUsage(ContextMenuUsage.ExplorerAndReview)]
		public void Properties(string pathlist)
		{
			RemoteEventRaiser.RaiseOpenMonitorForm
				(this, new RemoteEvents.LizardEventArgs(GetPaths(pathlist), FormTypes.Properties));
		}

		[ContextMenu("about", "About")]
		[ContextMenuUsage(ContextMenuUsage.ExplorerOnly)]
		public void About(string pathlist)
		{
			RemoteEventRaiser.RaiseMessageBox(this, new RemoteEvents.LizardEventArgs("LizardTF Version 0.3\nBy IFBC 2007\nian@smallwalrus.com\n\nTFVC Shell Extention Client\n"));
		}

		public Dictionary<string, ContextMenuAttribute> GetMenus(string pathlist)
		{
			return GetMenus(pathlist, ContextMenuUsage.ExplorerOnly);
		}

		public Dictionary<string, ContextMenuAttribute> GetMenus(string pathlist, ContextMenuUsage usage)
		{
			FileType overallFileType = GetFileType(GetPaths(pathlist));
			Dictionary<string, ContextMenuAttribute> menus = new Dictionary<string, ContextMenuAttribute>();
			MethodInfo[] mis = this.GetType().GetMethods();
			bool allowSeperator = false;
			foreach (MethodInfo mi in mis)
			{
				ContextMenuAttribute cmAttr = null;
				bool isValid = false;
				foreach (Attribute attr in mi.GetCustomAttributes(false))
				{
					if (attr is ContextMenuAttribute)
						cmAttr = (ContextMenuAttribute)attr;
					if (attr is ContextMenuUsageAttribute)
					{
						ContextMenuUsageAttribute cmua = (ContextMenuUsageAttribute)attr;
						isValid = ((usage & cmua.Usage) != ContextMenuUsage.None);
					}
				}
				if (cmAttr != null && isValid && (allowSeperator || !cmAttr.Text.StartsWith("-")))
				{
					if (cmAttr.TypeRequirements == FileType.None || ((cmAttr.TypeRequirements & overallFileType) != FileType.None))
					{
						cmAttr.Disabled = (cmAttr.DisabledRequirements != FileType.None) && ((cmAttr.DisabledRequirements & overallFileType) == FileType.None);
						menus.Add(cmAttr.Name, cmAttr);
						allowSeperator = !cmAttr.Text.StartsWith("-");
					}
				}
			}

			return menus;
		}

		public void ParseSingleFile(String path)
		{
			TFServerConnection connection = ServerConnections.GetConnectionForPath(path);
			WorkspaceOperators wso = new WorkspaceOperators(connection, connection.GetWorkspace(path));
			wso.ParseSingleFile(path);
		}

		public void RunMenuCommand(int ordinal, string pathList, ContextMenuUsage usage)
		{
			string[] paths = GetPaths(pathList);
			FileType overallFileType = GetFileType(GetPaths(pathList));
			MethodInfo[] mis = this.GetType().GetMethods();
			int i = 1;
			bool allowSeperator = false;
			ContextMenuAttribute cmAttr = null;
			bool isValid = false;
			foreach (MethodInfo mi in mis)
			{
				cmAttr = null; ;
				foreach (Attribute attr in mi.GetCustomAttributes(false))
				{
					if (attr is ContextMenuAttribute)
						cmAttr = (ContextMenuAttribute)attr;
					if (attr is ContextMenuUsageAttribute)
					{
						ContextMenuUsageAttribute cmua = (ContextMenuUsageAttribute)attr;
						isValid = ((usage & cmua.Usage) != ContextMenuUsage.None);
					}
				}

				if (cmAttr != null && isValid && (allowSeperator || !cmAttr.Text.StartsWith("-")))
				{
					if (cmAttr.TypeRequirements == FileType.None || ((cmAttr.TypeRequirements & overallFileType) != FileType.None))
					{
						if (ordinal == i)
						{
							//								File.WriteAllText(ServerConnections.GetConnectionForPath(paths[0]).Settings.TempPath + "\\menurequest.txt", string.Format("MenuItem:{0} Path:{1}", ordinal, pathList));
							mi.Invoke(this, new object[] { pathList });
							return;
						}
						allowSeperator = !cmAttr.Text.StartsWith("-");
						i++;
					}
				}
			}
		}



		public string[] GetPaths(string pathList)
		{
			if (pathList.IndexOf('"') < 0)
				return new string[] { pathList };
			bool inName = false;
			List<string> paths = new List<string>();
			StringBuilder sb = new StringBuilder();
			for (int i = 0; i < pathList.Length; i++)
			{
				string c = pathList.Substring(i, 1);
				if (!inName)
				{
					if (c == "\"")
						inName = true;
				}
				else
				{
					if (c == "\"")
					{
						if (sb.ToString().Trim() != string.Empty)
							paths.Add(sb.ToString());
						sb = new StringBuilder();
						inName = false;
					}
					else
						sb.Append(c);
				}

			}
			return paths.ToArray();
		}

		private FileType GetFileType(string[] pathList)
		{
			if (pathList.Length == 0)
				return FileType.Versioned | FileType.OutOfDate;
			string[] names = Enum.GetNames(typeof(FileType));
			Dictionary<FileType, int> typeCount = new Dictionary<FileType, int>();
			foreach (string name in names)
			{
				typeCount.Add((FileType)Enum.Parse(typeof(FileType), name), 0);
			}
			foreach (string file in pathList)
			{
				TFServerConnection connection = ServerConnections.GetConnectionForPath(file);
				FileType[] types = GetFileTypes(connection, file);
				foreach (FileType ft in types)
				{
					typeCount[ft]++;
				}
			}
			FileType result = FileType.None;
			foreach (KeyValuePair<FileType, int> kvp in typeCount)
			{
				if (kvp.Value == pathList.Length)
					result |= kvp.Key;
			}
			result |= FileType.SingleFile;
			if (pathList.Length != 1 || typeCount[FileType.SingleFile] != 1)
			{
				result ^= FileType.SingleFile;
			}
			result |= FileType.TwoFiles;
			if (pathList.Length != 2 || typeCount[FileType.SingleFile] != 2)
			{
				result ^= FileType.TwoFiles;
			}
			if (typeCount[FileType.SingleFolder] > 0 && !((result & FileType.SingleFolder) == FileType.SingleFolder))
				result |= FileType.Mixed;
			result |= FileType.SingleFolder;
			if (pathList.Length != 1 || typeCount[FileType.SingleFolder] != 1)
			{
				result ^= FileType.SingleFolder;
			}
			if (typeCount[FileType.SingleFolder] == pathList.Length)
				result |= FileType.AllFolders;
			if (typeCount[FileType.SingleFile] == pathList.Length)
				result |= FileType.AllFiles;
			if (pathList.Length == 1)
				result |= FileType.SingleItem;

			return result;
		}

		private FileType[] GetFileTypes(TFServerConnection connection, string file)
		{
			if (file == string.Empty)
				return new FileType[] { };

			List<FileType> types = new List<FileType>();
			if (File.Exists(file))
				types.Add(FileType.SingleFile);
			else if (Directory.Exists(file))
				types.Add(FileType.SingleFolder);
			Workspace ws = connection.VersionControlServer.TryGetWorkspace(file);
			Item item = null;
			if (ws != null)
			{
				types.Add(FileType.InWorkspace);
				try
				{
					item = connection.VersionControlServer.GetItem(ws.GetServerItemForLocalItem(file));
				}
				catch
				{
					item = null;
				}
				if (item == null)
				{
					bool versioned = false;
					ExtendedItem[] extItems =
						ws.GetExtendedItems(new ItemSpec[] { new ItemSpec(file, RecursionType.None) }, DeletedState.Any, ItemType.Any)[0];
					if (extItems.Length > 0)
					{
						ExtendedItem extItem = extItems[0];
						if ((extItem.ChangeType | ChangeType.Add) == extItem.ChangeType)
							types.Add(FileType.Added);
						if ((extItem.ChangeType | ChangeType.Rename) == extItem.ChangeType)
						{
							types.Add(FileType.Versioned);
							types.Add(FileType.CheckedOut);
						}
						if (extItem.VersionLatest != extItem.VersionLocal && extItem.VersionLatest != 0)
						{
							types.Add(FileType.Versioned);
							types.Add(FileType.OutOfDate);
							versioned = true;
						}

					}
					if (!versioned)
						types.Add(FileType.Unversioned);

				}
				else
				{
					types.Add(FileType.Versioned);
					ExtendedItem extItem =
						ws.GetExtendedItems(new ItemSpec[] { new ItemSpec(file, RecursionType.None) }, DeletedState.Any, ItemType.Any)[0][0];
					if (extItem.VersionLatest != extItem.VersionLocal)
						types.Add(FileType.OutOfDate);
					if (extItem.ChangeType == ChangeType.None)
						types.Add(FileType.CheckedIn);
					else
					{
						types.Add(FileType.CheckedOut);
						if ((extItem.ChangeType & ChangeType.Lock) == ChangeType.Lock)
							types.Add(FileType.Locked);
						if (extItem.VersionLatest != extItem.VersionLocal)
							types.Add(FileType.Conflict);
					}
				}
			}
			else
			{
				types.Add(FileType.NotInWorkspace);
			}

			return types.ToArray();
		}

		public void Lizardenate(string pathList, bool recurse)
		{
			Lizardenator lz = new Lizardenator();
			lz.Lizardenate(pathList, recurse);
			StatusScan(pathList);

		}

		public string GetColData(int colIdx, string fileName)
		{
			string result = string.Empty;
			// Ignore directories
			if (Directory.Exists(fileName))
				return string.Empty;
			// Only service known columns
			if (colIdx < 0 || colIdx > 4)
				return string.Empty;
			try
			{
				string folderName = Path.GetDirectoryName(fileName);
				string ltfvcFolder = ServerConnections.GetConnectionForPath(fileName).GetMetaFolder(folderName);
				string ltfvcFile = Path.Combine(ltfvcFolder, Path.GetFileName(fileName) + ".ltfvc");


				if (Directory.Exists(ltfvcFolder))
				{
					if (File.Exists(ltfvcFile))
					{
						LizardFileInfo fi = GetFileInfoFromFile(ltfvcFile);
						switch (colIdx)
						{
							case 0:
								result = fi.Status.ToString();
								break;
							case 1:
								result = fi.ChangeType;
								break;
							case 2:
								result = fi.LockStatus;
								break;
							case 3:
								result = fi.ServerVersion.ToString();
								break;
							case 4:
								result = fi.LocalVersion.ToString();
								break;
						}
					}
				}

			}
			catch (UnauthorizedAccessException e)
			{
				return string.Empty;
			}
			catch (Exception e)
			{
				//			MessageBox.Show(e.Message);
				return string.Empty;
			}

			return result;
		}

		private string noBlanks(string inStr)
		{
			return (string.IsNullOrEmpty(inStr)) ? "_" : inStr;
		}

		public string GetFileInfos(string pathName)
		{
			// to make things a little quicker, the GetFilesForOverlayType reads all the files and stores everything
			// so this method can just call that, and then the data will be fetched if it wasn't already waiting...
			if (pathName != lastOverlayFolderName || fileInfos == null)
			{
				GetFilesForOverlayType(pathName, string.Empty);
			}
			if (fileInfos != null)
			{
				string result = string.Join("`", fileInfos.ToArray());
				fileInfos = null;
				return result;
			}
			else
			{
				return string.Empty;
			}



		}


		private string lastOverlayFolderName;
		private Dictionary<string, List<string>> fileListsByOverlayTypes;
		private List<string> fileInfos = new List<string>();


		public string GetFilesForOverlayType(string pathName, string overlayType)
		{
			TFServerConnection connection = ServerConnections.GetConnectionForPath(pathName);
			//if (pathName.EndsWith(ServerConnections.Connection.Settings.LtfMetaFolderName))
			//  pathName = pathName.Substring(0, pathName.Length - ServerConnections.Connection.Settings.LtfMetaFolderName.Length - 1);
			string result = string.Empty;
			// Ignore directories
			//pathName = "C:\\OryxProjects\\LizardTF\\Trunk\\MonitorLizard\\Helpers";
			if (!Directory.Exists(pathName))
				return string.Empty;
			if (!Directory.Exists(connection.GetMetaFolder(pathName)))
				return string.Empty;

			List<string> matches = new List<string>();
			if (lastOverlayFolderName == pathName && fileListsByOverlayTypes != null && fileListsByOverlayTypes.ContainsKey(overlayType))
			{
				matches = fileListsByOverlayTypes[overlayType];
				fileListsByOverlayTypes.Remove(overlayType);
			}
			else
			{
				fileListsByOverlayTypes = new Dictionary<string, List<string>>();
				fileInfos = new List<string>();
				string ltfvcFolder = connection.GetMetaFolder(pathName);
				foreach (string lizardOverLayStatus in Enum.GetNames(typeof(LizardOverLayStatus)))
					fileListsByOverlayTypes.Add(lizardOverLayStatus, new List<string>());

				lastOverlayFolderName = pathName;

				ParseFolder(pathName);

				if (Directory.Exists(ltfvcFolder))
				{
					foreach (string fileName in Directory.GetFiles(pathName))
					{
						try
						{
							string ltfvcFile = Path.Combine(ltfvcFolder, Path.GetFileName(fileName) + ".ltfvc");


							if (File.Exists(ltfvcFile))
							{
								LizardFileInfo fi = GetFileInfoFromFile(ltfvcFile);
								if (fi.OverlayType.ToString() == overlayType)
								{
									matches.Add(Path.GetFileName(fileName));
								}
								else
								{
									fileListsByOverlayTypes[fi.OverlayType.ToString()].Add(Path.GetFileName(fileName));
								}

								// get all file info
								List<string> infos = new List<string>();
								infos.Add(fileName);
								infos.Add(noBlanks(fi.ChangeType.ToString()));
								infos.Add(noBlanks(fi.Status.ToString()));
								infos.Add(noBlanks(fi.ServerVersion.ToString()));
								infos.Add(noBlanks(fi.LocalVersion.ToString()));
								infos.Add(noBlanks(fi.OverlayType.ToString()));
								infos.Add(noBlanks(fi.LockStatus));
								infos.Add(noBlanks(fi.LockOwner));
								infos.Add(noBlanks(fi.HasOtherPendingChange.ToString()));
								infos.Add(noBlanks(fi.OtherUsers));

								string infoStr = string.Join("|", infos.ToArray());
								fileInfos.Add(infoStr);

							}
						}


						catch (UnauthorizedAccessException e)
						{
							return string.Empty;
						}
						catch (Exception e)
						{
							//			MessageBox.Show(e.Message);
							return string.Empty;
						}
					}
					foreach (string dir in Directory.GetDirectories(pathName))
					{
						string dirLtfvcFolder = connection.GetMetaFolder(dir);
						if (Directory.Exists(dirLtfvcFolder))
						{
							string dirLtfvcFile = Path.Combine(dirLtfvcFolder, "ltfvc.folderstatus");
							if (!File.Exists(dirLtfvcFile))
							{
								ParseFolder(dir);
							}
							if (File.Exists(dirLtfvcFile))
							{
								string dirStatus = File.ReadAllText(dirLtfvcFile);
								if (dirStatus == overlayType)
								{
									matches.Add(Path.GetFileName(dir));
								}
								else
								{
									fileListsByOverlayTypes[dirStatus].Add(Path.GetFileName(dir));
								}
							}
						}
					}
				}
			}
			result = "|" + string.Join("|", matches.ToArray()) + "|";
			return result;
		}


		public static LizardFileInfo GetFileInfoFromFile(string fileName)
		{
			LizardFileInfo fileInfo = null;
			string binaryFileName = fileName + ".bin";
			// use the binary version if it exists
			if (File.Exists(binaryFileName))
			{
				BinaryFormatter bf = new BinaryFormatter();
				using (Stream s = new FileStream(binaryFileName, FileMode.Open))
				{
					fileInfo = (LizardFileInfo)bf.Deserialize(s);
				}
				return fileInfo;
			}
			XmlSerializer xs = new XmlSerializer(typeof(LizardFileInfo));
			using (Stream s = new FileStream(fileName, FileMode.Open))
			{
				fileInfo = (LizardFileInfo)xs.Deserialize(s);
			}
			return fileInfo;
		}
	}
}
